# deliverance pyquery rules

from pyquery import  PyQuery as pq
import re
from urlparse import urlsplit,urlparse
from cgi import parse_qs
import urllib
import gzip
import StringIO
import socket
import urllib2
import logging as logger

APP_MAPPINGS = {u'cynin': u'twg', u'dspace': u'federated-repositories',
                u'apkn': u'apkn-portal', u'twg': u'twg'}

# set default socket timeouts
default_timeout = 300
socket.setdefaulttimeout(default_timeout)

re_country = '/apex/country-folders/[a-zA-Z\-0-9]+[/]?.*$'
re_dir_search = '/apex/country-folders/directory-search[/]?.*$'
re_country_folder_root = '/apex/country-folders[/]?$'
re_other_apps = '/dspace[[/][.]*]?|/twg[[/][.]*]?|/cynin[[/][.]*]?|/xmlui[[/][.]*]?'
re_conference_documentation = '/conference-documentation/.*$'
custom_nav_url = "http://%s:9000/Plone/@@get-custom-navigator"
custom_ftr_url = "http://%s:9000/Plone/@@get-common-footer"
conferences_nav_url = "http://%s:9000/Plone/@@get-conference-header"
language_query_param = 'set_language'
dspace_content_url = "http://%s:9000/dspace/xmlui/apkn-remote-search\
?metaType=%s&communityName=%s"
dspace_content_filter = "go=DigitalRepository"
digital_repository_types = "Article"
CUSTOM_NAVIGATOR_CSS = "<link href=\"/++resource++plonetheme.apkntheme.stylesheets/customnav.css\" \
    rel=\"stylesheet\" type=\"text/css\" id=\"common-nav-css\" />"
CUSTOM_NAVIGATOR_CSS_GRID = "<link href=\"/++resource++plonetheme.apkntheme.stylesheets/custom-nav-grid.css\" \
    rel=\"stylesheet\" type=\"text/css\" id=\"common-nav-grid\" />"

DSPACE_PORTLET_URL = "http://%s:8082/Plone/@@load-dspace-portlet"

APPLY_THEME_PARAM = "themepath"

def match_digital_repository(req, resp, headers, *args):
    match = False
    if len(re.findall(re_country, req.path_info)) == 1:
        match = True
    return match

def match_default_route(req, resp, headers, *args):
    match = True
    logger.info("Checking path info for match: PATH @@ %s", req.path_info)
    if len(re.findall(re_other_apps, req.path_info)) > 0:
        match = False
    return match

def get_host_name(request):
    host_address = "127.0.0.1"
    try:
        host_address = request.environ.get('HTTP_HOST', None)
        if host_address is None:
            host_address = request.environ['HTTP_HOST']
        try:
            host_address = host_address.split(":")[0]
        except:
            pass
    except:
        logger.error("Error extraccting host address from environ")
    logger.info("Extracted host address as %s", host_address)
    return host_address

def match_country_folder_root(req, resp, headers, *args):
    match = False
    if len(re.findall(re_country_folder_root, req.path_info)) == 1:
        match = True
    return match

def match_digital_repository_country(req, resp, headers, *args):
    match = False
    if len(re.findall(re_country, req.path_info)) == 1:
        #country folder matches
        if req.query_string.startswith(dspace_content_filter):
            match = True
    return match

def load_url_content(url, headers):
    http_request = urllib2.Request(url, None, headers)
    http_request.add_header('Content-Length', '0')
    response = urllib2.urlopen(http_request)
    response_content = pq(response.read())
    final_response_content = response_content("body").html()
    return final_response_content

def decompress_response(response):
    compressed = response.read()
    compressed_stream = StringIO.StringIO(compressed)
    unzipper = gzip.GzipFile(fileobj=compressed_stream)
    return unzipper.read()

def match_country_folder(req, resp, headers, *args):
    '''
    match a request for country folder in apex
    '''
    match = False
    if len(re.findall(re_country, req.path_info)) == 1:
        match = True
    if len(re.findall(re_dir_search, req.path_info)) == 1:
        match = False
    return match

def fix_dspace_item_links(doc_content):
    links = doc_content("a[href^='/xmlui']")
    for link in links:
        link_target = "/dspace" + link.get('href')
        pq(link).attr('href', link_target)
    return doc_content

def get_dspace_items(request, context, item_type = None):
    country = get_country(request)
    host_name = get_host_name(request)
    if not item_type:
        dspace_url = dspace_content_url %(host_name, "Article", country)
    else:
        dspace_url = dspace_content_url %(host_name, item_type, country)
    ds_request = urllib2.Request(dspace_url)
    try:
        response = urllib2.urlopen(ds_request)
        doc_response = response.read()
        resp_item = pq(doc_response)
        if context == 'country-folders':
            doc_content = resp_item("#aspect_apknauth_RemoteSearch_table_resultsTable")
        elif context == 'country':
            doc_content = resp_item("#content")
        doc_content_final = fix_dspace_item_links(doc_content)
    except:
        doc_content_final = None
    return doc_content_final

def load_dspace_items(content, theme, resource_fetcher, log, context):
    request = log.request
    q_string = request.query_string
    content_filter = request.GET.get("show")
    dspace_content = get_dspace_items(request, context, content_filter)
    if dspace_content:
        if context == 'country-folders':
            theme("#cf_repository_box").html(pq(dspace_content))
        elif context == 'country':
            theme(".cf_message").after(pq(dspace_content))
            theme(".cf_message").remove()

def load_dspace_apex_portlet(content, theme, resource_fetcher, log):
    FINAL_URL = DSPACE_PORTLET_URL %(get_host_name(log.request))
    portlet_content = load_url_content(FINAL_URL, log.request.headers)
    theme("#sidebar").append(portlet_content)

def fix_country_folder(content, theme, resource_fetcher, log):
    '''
    Fix Country Folder Portlets
    '''
    #theme("#portal-column-one").remove()
    #theme("#portal-column-content").css("margin-left","0px")
    pass

def patch_portlets(content, theme, resource_fetcher, log):
    '''
    Remove Empty Portlets and Resize Main Column
    '''
    rhs_portlet = theme("#portal-column-two")
    has_portlets = rhs_portlet(".portletHeader").length
    if not has_portlets:
        pq(rhs_portlet).remove()
        theme("#portal-column-content").css('margin-right','0em')
    lhs_portlet = theme("#portal-column-one")
    has_portlets = lhs_portlet(".portletHeader")
    if not has_portlets:
        pq(lhs_portlet).remove()
        theme("#portal-column-content").css('margin-left', '0em')


def fix_dspace_media_links(content, theme, resource_fetcher, log):
    head_links = theme("head link[href^='/xmlui']")
    for link in head_links:
        link_target = "/dspace" + link.get('href')
        pq(link).attr('href', link_target)

    head_scripts = theme("head script[src^='/xmlui']")
    for link in head_scripts:
        link_target = "/dspace" + link.get('src')
        pq(link).attr('src', link_target)

    body_links = theme("a[href^='/xmlui']")
    for link in body_links:
        link_target = "/dspace" + link.get('href')
        pq(link).attr('href', link_target)
    
    webforms = theme("form[action^='/xmlui']")
    for webform in webforms:
        form_target = "/dspace" + webform.get('action')
        pq(webform).attr('action', form_target)
    images = theme("img[src^='/xmlui']")
    for image in images:
        image_source = "/dspace" + image.get('src')
        pq(image).attr('src', image_source)
    handle_links = theme("a[href^='http://hdl.handle.net']")
    for link in handle_links:
        local_handle = link.get('href').replace('http://hdl.handle.net','')
        link_target = '/dspace/xmlui/handle' + local_handle
        pq(link).attr('href', link_target)
        pq(link).text(link_target)


def fix_cynin_media_links(content, theme, resource_fetcher, log):
    """ fix broken cynin media links """
    com_nav_links = theme('img')
    for link in com_nav_links:
        if (link.get('src').find('/cynin') > 0) and \
        (link.get('src').find('++resource++language-flags') == -1):
            link_target = link.get('src').replace('twg/cynin','twg')
            pq(link).attr('src',link_target)
        if link.get('src').find('++resource++language-flags') > 0 or \
            link.get('src').find('++resource++country-flags') >0:
            link_target = link.get('src').replace('cynin/','twg')
            pq(link).attr('src',link_target)
            pq(link).parent().append(link.get('title'))
        if link.get('src').find('++resource++country-flags') > 0:
            link_target = link.get('src').replace('country-flags','language-flags')
            pq(link).attr('src', link_target)
        if link.get('src').find('/cynin') > 0:
            link_target = link.get('src').replace('/cynin', '/twg')
            pq(link).attr('src', link_target) 
    # fix broken comment form - URL hardcoded in Plone
    comment_form = theme("#commentscontainer form")
    if comment_form:
        action_url = comment_form.attr("action")
        if action_url.find('/twg/login_form') > 0:
            action_url = action_url.replace('/twg/login_form',\
            '/login_form')
            pq(comment_form).attr("action",action_url)
    #temporary fix for swahili selector
    #to migrate to custom viewlet
    sw_selector = theme("li.language-sw")
    if sw_selector:
        img_data = pq("<img width='16' height='13' alt='Swahili' \
        src='/++resource++language-flags/sw.gif' title='Swahili'>")
        link = pq("a", pq(sw_selector))
        pq(link).html(img_data)

    js_links = theme("script")
    for js in js_links:
        if js.get("src"):
            if js.get("src").find("/cynin") > 0:
                link_target = js.get("src").replace("/cynin","/twg", 1)
                pq(js).attr("src", link_target)
    style_links = theme("link")
    for sl in style_links:
        if sl.get("href"):
            if sl.get("href").find("/cynin") > 0:
                link_target = sl.get("href").replace("/cynin","/twg",1)
                pq(sl).attr("href", link_target)
    import_links = theme("style")
    for il in import_links:
        if il.text.startswith("@import"):
            ntext = il.text.replace("/cynin", "/twg", 1)
            pq(il).text(ntext)


def cynin_polish(content,theme, resource_fetcher, log):
    cyninHelpBox = theme("li.smallwhitebutton").parent().parent()
    if cyninHelpBox:
        pq(cyninHelpBox).remove()
    theme(".commentsblock").addClass(u'notranslate')

def patch_cynin_links(content, theme, resource_fetcher, log):
    links = theme("a")
    for link in links:
        if str(link.get("href")).find("/cynin") > 0:
            link_target = link.get("href").replace("/cynin","/twg", 1)
            pq(link).attr("href", link_target)
    flash_links = theme("object")
    for fl in flash_links:
        if str(fl.get("data")).find("/cynin") > 0:
            link_target = fl.get("data").replace("/cynin","/twg", 1)
            pq(fl).attr("data", link_target)
    
def patch_user_links(content, theme, resource_fetcher, log, app_id):
    if app_id == 'cynin':
        # match cynin user personalization links - rewrite to main Plone
        lre = ".*/twg/personalize_form|.*/twg/author/.*|.*/twg/password_form"
        # match broken language switch links in cynin 
        lre_lang = ".*_vh_cynin.*"
        page_links = theme("a")
        for link in page_links:
            if re.match(lre, str(link.get('href'))) is not None:
                link_target = link.get("href").replace("cynin/", "")
                pq(link).attr('href', link_target)
                break
            if re.match(lre_lang, str(link.get('href'))) is not None:
                link_target = link.get('href').replace("/_vh_cynin","")
                pq(link).attr('href', link_target)
        avatar_links = theme("a.avatarlink")
        for link in avatar_links:
            if str(link.get("rel")).find("/cynin") > 0:
                rel_target = link.get("rel").replace("/cynin","/twg", 1)
                pq(link).attr("rel", rel_target)

def get_custom_navigator_content(request, app_id):
    css_text = CUSTOM_NAVIGATOR_CSS + CUSTOM_NAVIGATOR_CSS_GRID
    nav_url = custom_nav_url %(get_host_name(request))
    query_string = request.environ.get('QUERY_STRING')
    path_info = request.environ.get('PATH_INFO')
    drop = []
    if len(re.findall(re_conference_documentation, path_info)) > 0:
        #set navigation url to conference headers
        nav_url = conferences_nav_url %(get_host_name(request))
        
        drop.append("#portal-breadcrumbs")
        
    qparams = {'app_id': APP_MAPPINGS[app_id], 'path': path_info}
    path_info_encoded = urllib.urlencode(qparams)
    c_menu = "<p>&nbsp;</p>"
    if query_string.startswith('set_language'):
        nav_url += '?%s&%s' %(query_string, path_info_encoded)
    else:
        nav_url += "?" + path_info_encoded
    cnav_request = urllib2.Request(nav_url, None, request.headers)
    cnav_request.add_header('Content-Length','0')
    try:
        response = urllib2.urlopen(cnav_request)
        if response.headers.get("Content-Encoding") == 'gzip':
            nav_response = decompress_response(response)
        else:
            nav_response = response.read()
        c_menu = pq(nav_response)
    except Exception, e:
        logger.error("Unable to get custom navigator with error: %s - URL @@ %s", 
        e.__str__(), nav_url)
    return (c_menu,css_text, drop)

def get_custom_footer_content(request):
    nav_url = custom_ftr_url %(get_host_name(request))
    query_string = request.environ.get('QUERY_STRING')
    if query_string.startswith('set_language'):
        nav_url += '?%s' %(query_string)
    footer_request = urllib2.Request(nav_url, None, request.headers)
    footer_request.add_header('Content-Length', '0')
    response = urllib2.urlopen(footer_request)
    if response.headers.get("Content-Encoding") == "gzip":
        nav_response = decompress_response(response)
    else:
        nav_response = response.read()
    c_footer = pq(nav_response).children()
    return c_footer

def load_custom_navigator(content, theme, resource_fetcher, log, app_id):
    drop = []
    if app_id == 'cynin':
        c_menu, css_text, drop =\
         get_custom_navigator_content(log.request, app_id)
        if c_menu:
            theme("#header").before(c_menu.html())
        theme("head").append(css_text)
    elif app_id == 'dspace':
        q_string = log.request.query_string
        if APPLY_THEME_PARAM in q_string:
            logger.info("Skipping header insertion - Theme override detected")
        else:
            c_menu, css_text, drop =\
             get_custom_navigator_content(log.request, app_id)
            theme("#ds-header").prepend(pq(c_menu).html())
            theme("head").append(css_text)
    elif app_id == 'apkn':
        c_menu, css_text, drop = \
        get_custom_navigator_content(log.request, app_id)
        theme("#portal-top").prepend(c_menu("body").html())
        theme("head").append(css_text)
    else:
        pass
    
    if drop:
        for drop_item in drop:
            theme(drop_item).remove()

def load_custom_footer(content, theme, resource_fetcher, log, app_id):
    if app_id == 'cynin':
        c_footer = get_custom_footer_content(log.request)
        theme("#apkn-common-branding").empty().html(c_footer.html())
    elif app_id == 'dspace':
        q_string = log.request.query_string
        if APPLY_THEME_PARAM in q_string:
            logger.info("Skipping footer insertion - Theme override detected")
        c_footer = get_custom_footer_content(log.request)
        theme("#footer").empty().html(c_footer.html())
    elif app_id == 'apkn':
        c_footer = get_custom_footer_content(log.request)
        theme("#apkn-footer-view").empty().html(c_footer.html()).\
        attr('id','')
    else:
        pass

def update_attributes(content, theme, resource_fetcher, log):
    all_ttds = theme("td#extrarow")
    for ttd in all_ttds:
        pq(ttd).addClass("CollapsedTableText")
        
    links = theme("a")
    for link in links:
        if str(link.get("href")).find(":5000") == 1:
            new_href = link.get("href").replace(":5000", "")
            pq(link).attr("href", new_href)

def move_elements(content, theme, resource_fetcher, log, app_id):
    #0 - do nothing, 1 - prepend 2- Append
    map_apkn = (('#portal-siteactions','#apkn-common-brand', '#apkn-default-nav', 0),\
    ('#portal-searchbox','#apkn-search-place-holder',
    '#apkn-search-place-holder', 0))
    map_cynin = (('#lsboxholder','#apkn-search-place-holder',
    '#apkn-search-place-holder',0),)
    map_dspace = (('#ds-search-option','#apkn-search-place-holder',
    '#apkn-search-place-holder',0),)
    
    theme("#ds-search-option").prev("h3").remove();

    def replacer(els_map, where):
        if where == 'theme':
            for pair in els_map:
                copy_of = theme(pair[0])
                if copy_of:
                    container = theme(pair[1])
                    container_pub = theme(pair[2])
                    if container:
                        theme(pair[0]).remove()
                        if pair[3] == 1: #append
                            pq(container).prepend(pq(copy_of))
                        elif pair[3] == 2:
                            pq(container).append(pq(copy_of))
                    elif container_pub:
                        theme(pair[0]).remove()
                        if pair[3] == 1: #append
                            pq(container_pub).prepend(pq(copy_of))
                        elif pair[3] == 2:
                            pq(container_pub).append(pq(copy_of))
                    else:
                        theme(pair[0]).remove()
    if app_id == 'apkn':
        replacer(map_apkn, 'theme')
        theme(".documentFirstHeading").wrap('<div class="documentFirstHeadingWrapper" />')
    elif app_id == 'cynin':
        replacer(map_cynin, 'theme')
        theme(".adderbar").remove()
        theme("div.accordiontab:first").remove()
        theme("div.navTreeHomeholder:eq(1)").remove()
        theme("div.fieldUploadFile").remove();
        authBox = theme("#commonUserBox")
        if not authBox:
            #remove auth only elements to clean up ui
            theme("#sidenavigationlogoholder").remove()
    elif app_id == 'dspace':
        replacer(map_dspace, 'theme')

def position_language_selector(content, theme, resource_fetcher, log):
    '''
    Set up a unified language selector
    '''
    
    def clean_links(links):
        for link in links:
            children = pq(link).children("img")
            pq(children).attr("height","13")
            pq(children).attr("width","16")
            pq(link).empty()
            pq(link).prepend(pq(children))

    lang_selector = theme("#portal-languageselector")
    if lang_selector:
        pq(lang_selector).remove()

def get_country(req):
    rpath = req.path_info
    country_name = None
    try:
        country_name = rpath.split('/')[-1].replace('/','').strip()
    except:
        pass
    return country_name


def get_host_address(req,country):
    remote_address = "http://" + req.host + "/dspace/xmlui/remoteview?"+\
    "CommunityIdentity=" + country
    return remote_address

def patch_portlet_links(content, theme, resource_fetcher, log):
    '''
    Temporary fix to remove link to Manage Portlets
    '''
    links = theme("a[href$='@@manage-portlets']")
    for link in links:
            pq(link).remove()

def clean_document(content, theme, resource_fetcher, log, app_id):
    '''
    Remove duplicate elements e.t.c
    '''
    if app_id == 'dspace':
        ds_logo = theme("#ds-header-logo").parent();
        pq(ds_logo).next("h1").remove();
        pq(ds_logo).next("h2").remove();
        pq(ds_logo).remove()
        uBox = theme("div.commonUserBox")
        if uBox:
            accBox = theme("#aspect_artifactbrowser_Navigation_list_account")
            accTitle = accBox.prev("h3")
            pq(accBox).remove()
            pq(accTitle).remove()
    return 1
    
    
def drop_document_element(content, theme, resource_fetcher, log, selector):
    theme(selector).remove()
